﻿// <copyright file="MainForm.cs" company="QUT">
//     Copyright (c) QUT. All rights reserved.
// </copyright>

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;

using GenerateKml.Properties;
using GenerateKml.Steps;
using Google.KML;
using Qut.GenerateKml.Business;
using Qut.GenerateKml.Data;
using Qut.GenerateKml.Data.FileDefinitions;

namespace GenerateKml
{
    /// <summary>
    /// The primary Windows form for the generate Kml application.
    /// </summary>
    public partial class MainForm : Form
    {
        /// <summary>
        /// The collection of steps (initialised at startup).
        /// </summary>
        private List<Step> _steps;

        /// <summary>
        /// The current step (default is -1).
        /// </summary>
        private int _currentStep = -1;

        /// <summary>
        /// The geographical data (MapInfo file).
        /// </summary>
        private MapInfoFile geographicalData;

        /// <summary>
        /// The document (result of translation).
        /// </summary>
        private geDocument document;

        /// <summary>
        /// The welcome step.
        /// </summary>
        private WelcomeStep stpWelcome;

        /// <summary>
        /// The load geographical data step.
        /// </summary>
        private LoadGeographicalDataStep stpLoadGeographicalData;

        /// <summary>
        /// The select columns step.
        /// </summary>
        private SelectColumnsStep stpSelectColumns;

        /// <summary>
        /// The load sociological data step.
        /// </summary>
        private LoadSociologicalDataStep stpLoadSociologicalData;

        /// <summary>
        /// The specify output file step.
        /// </summary>
        private SpecifyOutputFileStep stpSpecifyOutputFile;

        /// <summary>
        /// The summary step.
        /// </summary>
        private SummaryStep stpSummary;

        /// <summary>
        /// Initializes a new instance of the <see cref="MainForm"/> class.
        /// </summary>
        public MainForm()
        {
            InitializeComponent();
        }

        /// <summary>
        /// The different steps in the wizard.
        /// </summary>
        private enum StepOption
        {
            /// <summary>
            /// Welcome step
            /// </summary>
            Welcome,

            /// <summary>
            /// Load Geographical Data step
            /// </summary>
            LoadGeographicalData,

            /// <summary>
            /// Select MapInfo Columns step
            /// </summary>
            SelectMapInfoColumns,

            /// <summary>
            /// Load Sociological Data step
            /// </summary>
            LoadSociologicalData,

            /// <summary>
            /// Specify Output File step
            /// </summary>
            SpecifyOutputFile,

            /// <summary>
            /// Summary step
            /// </summary>
            Summary
        }

        /// <summary>
        /// Handles the Load event of the MainForm control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void MainForm_Load(object sender, EventArgs e)
        {
            this.InitialiseSteps();
            if (Configuration.ShowWelcomeScreen)
            {
                this.ShowStep(0);
            }
            else
            {
                this.ShowStep(1);
            }
        }

        /// <summary>
        /// Initialises the steps.
        /// </summary>
        private void InitialiseSteps()
        {
            this.stpWelcome = new WelcomeStep();
            this.stpLoadGeographicalData = new LoadGeographicalDataStep();
            this.stpSelectColumns = new SelectColumnsStep();
            this.stpLoadSociologicalData = new LoadSociologicalDataStep();
            this.stpSpecifyOutputFile = new SpecifyOutputFileStep();
            this.stpSummary = new SummaryStep();

            this._steps = new List<Step>();
            this._steps.Add(new Step() { Title = "Welcome", Control = this.stpWelcome });
            this._steps.Add(new Step() { Title = "Load Geographical Data", Control = this.stpLoadGeographicalData });
            this._steps.Add(new Step() { Title = "Select MapInfo Columns", Control = this.stpSelectColumns });
            this._steps.Add(new Step() { Title = "Load Sociological Data", Control = this.stpLoadSociologicalData });
            this._steps.Add(new Step() { Title = "Specify Output File", Control = this.stpSpecifyOutputFile });
            this._steps.Add(new Step() { Title = "Summary", Control = this.stpSummary });
            foreach (var step in this._steps)
            {
                StepsPanel.Controls.Add(step.Control);
                step.Control.Dock = DockStyle.Fill;
                step.Control.Visible = false;
            }
        }

        /// <summary>
        /// Shows the step.
        /// </summary>
        /// <param name="step">The step to be displayed.</param>
        private void ShowStep(int step)
        {
            if (this._currentStep != -1)
            {
                this._steps[this._currentStep].Control.Visible = false;
            }

            this._steps[step].Control.Visible = true;

            this.TitleLabel.Text = this._steps[step].Title;
            this._currentStep = step;
            this.BackButton.Enabled = this._currentStep > 0;
            this.NextButton.Enabled = this._currentStep < this._steps.Count - 1;
            this.CancelProcessButton.Enabled = this._currentStep < this._steps.Count - 1;
            if (this._currentStep == this._steps.Count - 1)
            {
                this.CloseButton.Visible = true;
                this.BackButton.Visible = false;
                this.NextButton.Visible = false;
                this.CancelProcessButton.Visible = false;
            }
        }

        /// <summary>
        /// Handles the Click event of the btnBack control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void BackButton_Click(object sender, EventArgs e)
        {
            this.ShowStep(this._currentStep - 1);
        }

        /// <summary>
        /// Handles the Click event of the btnNext control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void NextButton_Click(object sender, EventArgs e)
        {
            switch (this._currentStep)
            {
                case (int)StepOption.Welcome:
                    {
                        this.ShowStep(this._currentStep + 1);
                        break;
                    }

                case (int)StepOption.LoadGeographicalData:
                    {
                        this.LoadGeographicalData();
                        break;
                    }

                case (int)StepOption.SelectMapInfoColumns:
                    {
                        this.SelectMapInfoColumns();
                        break;
                    }

                case (int)StepOption.LoadSociologicalData:
                    {
                        this.LoadSociologicalData();
                        break;
                    }

                case (int)StepOption.SpecifyOutputFile:
                    {
                        this.TranslateData();
                        break;
                    }
            }
        }

        /// <summary>
        /// Handles the Click event of the btnCancel control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void CancelButton_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Cancel process?", "Cancel", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                this.Close();
            }
        }

        /// <summary>
        /// Handles the Click event of the btnClose control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void CloseButton_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// Loads the geographical data.
        /// </summary>
        private void LoadGeographicalData()
        {
            FileInfo mapInfoMIFFile, mapInfoMIDFile;
            try
            {
                mapInfoMIDFile = new FileInfo(this.stpLoadGeographicalData.MapInfoMIDFilePath);
                if (!mapInfoMIDFile.Exists || !mapInfoMIDFile.Extension.ToLower().EndsWith("mid") || mapInfoMIDFile.Length == 0)
                {
                    MessageBox.Show("The specified MapInfo MID file is invalid.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
            }
            catch (Exception)
            {
                MessageBox.Show("The specified MapInfo MID file is invalid.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            try
            {
                mapInfoMIFFile = new FileInfo(this.stpLoadGeographicalData.MapInfoMIFFilePath);
                if (!mapInfoMIFFile.Exists || !mapInfoMIFFile.Extension.ToLower().EndsWith("mif") || mapInfoMIFFile.Length == 0)
                {
                    MessageBox.Show("The specified MapInfo MIF file is invalid.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
            }
            catch (Exception)
            {
                MessageBox.Show("The specified MapInfo MIF file is invalid.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            try
            {
                var geographical = new GeographicalData();
                this.geographicalData = geographical.Load(mapInfoMIFFile.FullName, mapInfoMIDFile.FullName);
                var columns = new List<string>();
                foreach (DataColumn column in this.geographicalData.GetMidData().Columns)
                {
                    columns.Add(column.ColumnName);
                }

                this.stpSelectColumns.SetColumns(columns);
                this.ShowStep(this._currentStep + 1);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Selects the map info columns.
        /// </summary>
        private void SelectMapInfoColumns()
        {
            this.ShowStep(this._currentStep + 1);
        }

        /// <summary>
        /// Loads the sociological data.
        /// </summary>
        private void LoadSociologicalData()
        {
            SociologicalData sociological = new SociologicalData();
            if (!string.IsNullOrEmpty(this.stpLoadSociologicalData.SociologicalDataFilePath))
            {
                // Preload Sociological data file
                try
                {
                    sociological.PreloadQldFederalResultsByElectorate2004(this.stpLoadSociologicalData.SociologicalDataFilePath);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format("An error has occured ({0}) attempting to process {1}, please specify a valid file and click next to continue.", ex.Message, this.stpLoadSociologicalData.SociologicalDataFilePath), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                this.stpSummary.UpdateOutputLog(sociological.GetMissingDivision(this.geographicalData).ToArray<string>());
            }

            bool mappingProvided = !string.IsNullOrEmpty(this.stpLoadSociologicalData.MappingDataFilePath);
            bool results2004Provided = !string.IsNullOrEmpty(this.stpLoadSociologicalData.Results2004DataFilePath);
            bool results2006Provided = !string.IsNullOrEmpty(this.stpLoadSociologicalData.Results2006DataFilePath);
            bool twoPartyPreferred2004Provided = !string.IsNullOrEmpty(this.stpLoadSociologicalData.TwoPartyPreferred2004DataFilePath);
            if (mappingProvided && results2004Provided && results2006Provided && twoPartyPreferred2004Provided)
            {
                // Preload Mapping data file
                try
                {
                    sociological.PreloadQldFederalStateElectorateMapping(this.stpLoadSociologicalData.MappingDataFilePath);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format("An error has occured ({0}) attempting to process {1}, please specify a valid file and click next to continue.", ex.Message, this.stpLoadSociologicalData.MappingDataFilePath), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                // Preload Results 2004 data file
                try
                {
                    sociological.PreloadFederalElectionResultsQld2004(this.stpLoadSociologicalData.Results2004DataFilePath);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format("An error has occured ({0}) attempting to process {1}, please specify a valid file and click next to continue.", ex.Message, this.stpLoadSociologicalData.Results2004DataFilePath), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                // Preload Results 2006 data file
                try
                {
                    sociological.PreloadQldStateResultsByElectorate2006(this.stpLoadSociologicalData.Results2006DataFilePath);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format("An error has occured ({0}) attempting to process {1}, please specify a valid file and click next to continue.", ex.Message, this.stpLoadSociologicalData.Results2006DataFilePath), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                // Preload Two Party Preferred 2004 data file
                try
                {
                    sociological.PreloadQldFederalResults2PartyPreferredByElectorate2004(this.stpLoadSociologicalData.TwoPartyPreferred2004DataFilePath);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format("An error has occured ({0}) attempting to process {1}, please specify a valid file and click next to continue.", ex.Message, this.stpLoadSociologicalData.TwoPartyPreferred2004DataFilePath), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            else if (mappingProvided || results2004Provided || results2004Provided || twoPartyPreferred2004Provided)
            {
                MessageBox.Show("Please supply ALL QLD Federal Electorate data files and then click next to continue.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            // Advance to next step
            this.ShowStep(this._currentStep + 1);
        }

        /// <summary>
        /// Translates the data.
        /// </summary>
        private void TranslateData()
        {
            string outputFilePath = this.stpSpecifyOutputFile.OutputFilePath;
            string extension = Path.GetExtension(outputFilePath);

            // If the extension does not exist then add it.
            if (extension == string.Empty)
            {
                if (!outputFilePath.EndsWith("."))
                {
                    outputFilePath += ".";
                }

                outputFilePath += "kml";
            }
            else if (extension.ToLower() != ".kml")
            {
                MessageBox.Show("Output file name must have KML extension.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (File.Exists(outputFilePath))
            {
                if (MessageBox.Show("The specified file exists, overwrite?", "File Exists", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
                {
                    return;
                }
            }

            try
            {
                Translator engine = new Translator();
                engine.AddColourMapping("ALP", Configuration.ALPColour);
                engine.AddColourMapping("LP", Configuration.LPColour);
                engine.AddColourMapping("NP", Configuration.NPColour);
                engine.AddColourMapping("DEM", Configuration.DEMColour);
                engine.AddColourMapping("GRN", Configuration.GRNColour);
                engine.AddColourMapping("OTH", Configuration.OTHColour);
                this.document = engine.Translate(this.geographicalData, this.stpSelectColumns.SelectedColumns);
                var kml = new geKML(this.document);
                File.WriteAllBytes(outputFilePath, kml.ToKML());
                this.ShowStep(this._currentStep + 1);
            }
            catch (IndexOutOfRangeException)
            {
                MessageBox.Show("Sociological Data does not match Geographical Data.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Handles the Click event of the HelpDocumentButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void HelpDocumentButton_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.Help.ShowHelp(this, "GenerateKML.chm", HelpNavigator.TableOfContents);
        }

        /// <summary>
        /// Handles the Click event of the SettingsButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void SettingsButton_Click(object sender, EventArgs e)
        {
            SettingsForm frmSettings = new SettingsForm();
            frmSettings.ShowDialog();
        }

        /// <summary>
        /// Represents a Step in the Wizard.
        /// </summary>
        private struct Step
        {
            /// <summary>
            /// Gets or sets the title.
            /// </summary>
            /// <value>The title.</value>
            public string Title { get; set; }

            /// <summary>
            /// Gets or sets the control.
            /// </summary>
            /// <value>The control.</value>
            public UserControl Control { get; set; }
        }
    }
}
